{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9a117e21",
   "metadata": {},
   "source": [
    "# VCOM窗口烧录——黄金分割搜索\n",
    "\n",
    "减少了新区间的内点采样测试，相比二分法，在16WQ智通上测试，减少了2次采样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cf4a83f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第一次执行：初始化JEITA mode\n",
      "0x31 43.38565\n",
      "0x4e 8.434434\n",
      "0x1e 11.5293\n",
      "0x3c 16.60662\n",
      "0x29 18.6191\n",
      "0x35 25.97687\n",
      "0x2e 26.27359\n",
      "0x32 42.24752\n",
      "0x30 33.57478\n",
      "best reg: 0x31 0x62 best JEITA: 43.38565 call times 9\n"
     ]
    }
   ],
   "source": [
    "from OpticalSensor import CA410Sensor as EyeSensor\n",
    "import numpy as np, time\n",
    "import jtoollib as jt\n",
    "\n",
    "from pic_window import *\n",
    "\n",
    "from scipy.optimize import minimize_scalar\n",
    "\n",
    "# D-VCOM取值范围，0x00->0x7F， 末位0为MTP，1为DAC\n",
    "\n",
    "\n",
    "sensor = EyeSensor(port='COM13')\n",
    "\n",
    "devices = jt.scan_devices_sn()\n",
    "handle = jt.open_device(devices[0])\n",
    "\n",
    "\n",
    "\n",
    "win = NonBlockingImageWindow(\"Demo\", size=(800, 800), fps=10)\n",
    "img = np.zeros((800, 800, 3), dtype=np.uint8)\n",
    "img[:, 0:800:2, 1] = 127\n",
    "win.update(img, fmt=\"rgb\")\n",
    "\n",
    "# 只在第一次运行时执行\n",
    "if 'JETA_flag' not in globals():\n",
    "    print(\"第一次执行：初始化JEITA mode\")\n",
    "    sensor.JETAmode()\n",
    "    _cell_flag_once = True\n",
    "else:\n",
    "    print(\"已进入Jeita mode。\")\n",
    "\n",
    "\n",
    "\n",
    "def get_data(x):\n",
    "    jt.i2c_write_no_reg(handle=handle, addr=0x9E, data=[ x<<1])\n",
    "    temp = sensor.GetJETA()\n",
    "    print(hex(x), temp)\n",
    "    return temp\n",
    "\n",
    "\n",
    "import math\n",
    "\n",
    "def argmax_golden_int(f, lo, hi, *, max_calls=None):\n",
    "    \"\"\"\n",
    "    在闭区间 [lo, hi] 的整数上，使用整数黄金分割搜索最大化 f(x)。\n",
    "    适用前提：f 在区间内近似单峰（unimodal）。\n",
    "    每轮仅新增一次函数采样；内部做了 memo 缓存避免重复调用。\n",
    "\n",
    "    返回: (best_x, best_val, calls)\n",
    "    \"\"\"\n",
    "    assert isinstance(lo, int) and isinstance(hi, int) and lo <= hi\n",
    "    phi_inv = (math.sqrt(5) - 1) / 2  # ≈ 0.618\n",
    "    cache = {}\n",
    "\n",
    "    def F(x):\n",
    "        if x not in cache:\n",
    "            cache[x] = f(x)\n",
    "        return cache[x]\n",
    "\n",
    "    if lo == hi:\n",
    "        return lo, F(lo), 1\n",
    "\n",
    "    # 初始两个内点（向整数对齐），保证 lo <= m1 < m2 <= hi\n",
    "    h = hi - lo\n",
    "    m1 = hi - int(round(phi_inv * h))\n",
    "    m2 = lo + int(round(phi_inv * h))\n",
    "    if m1 == m2:\n",
    "        # 退一步，确保两个点不同\n",
    "        if m2 < hi: m2 += 1\n",
    "        elif m1 > lo: m1 -= 1\n",
    "    m1 = max(lo, min(m1, hi))\n",
    "    m2 = max(lo, min(m2, hi))\n",
    "    if m1 > m2:\n",
    "        m1, m2 = m2, m1\n",
    "\n",
    "    f1, f2 = F(m1), F(m2)\n",
    "    calls_limit = float('inf') if max_calls is None else max_calls\n",
    "\n",
    "    # 主循环：每次只新增一个点的评估\n",
    "    while hi - lo > 3 and len(cache) < calls_limit:\n",
    "        if f1 < f2:           # 寻找最大值：右侧更高 -> 丢弃左段\n",
    "            lo = m1\n",
    "            m1, f1 = m2, f2   # 复用\n",
    "            h = hi - lo\n",
    "            m2 = lo + int(round(phi_inv * h))\n",
    "            if m2 == m1:      # 避免重复点\n",
    "                m2 = min(hi, m2 + 1)\n",
    "            f2 = F(m2)\n",
    "        else:                 # 左侧更高 -> 丢弃右段\n",
    "            hi = m2\n",
    "            m2, f2 = m1, f1   # 复用\n",
    "            h = hi - lo\n",
    "            m1 = hi - int(round(phi_inv * h))\n",
    "            if m1 == m2:\n",
    "                m1 = max(lo, m1 - 1)\n",
    "            f1 = F(m1)\n",
    "\n",
    "    # 收尾：区间很小时，暴力枚举（至多 4 个点），只补未算过的\n",
    "    best_x, best_v = None, -float('inf')\n",
    "    for x in range(lo, hi + 1):\n",
    "        v = F(x)\n",
    "        if v > best_v:\n",
    "            best_x, best_v = x, v\n",
    "    return best_x, best_v, len(cache)\n",
    "\n",
    "\n",
    "\n",
    "try:\n",
    "    best_x, best_val, calls = argmax_golden_int(get_data, 0x00, 0x7F)\n",
    "    print(\"best reg:\",hex(best_x), hex(best_x<<1), \"best JEITA:\",best_val, \"call times\", calls)\n",
    "    jt.i2c_write_no_reg(handle=handle, addr=0x9E, data=[ best_x<<1])\n",
    "\n",
    "finally:\n",
    "    jt.jtool.DevClose(handle)\n",
    "    win.stop()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4cbb3af",
   "metadata": {},
   "source": [
    "# VCOM烧录-二分法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e4f395d0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x40 36.27\n",
      "0x41 49.71\n",
      "mid: 64 low: 65 high: 127\n",
      "0x60 9.27\n",
      "0x61 9.01\n",
      "mid: 96 low: 65 high: 96\n",
      "0x50 15.07\n",
      "0x51 14.53\n",
      "mid: 80 low: 65 high: 80\n",
      "0x48 21.63\n",
      "0x49 20.5\n",
      "mid: 72 low: 65 high: 72\n",
      "0x44 29.02\n",
      "0x45 26.56\n",
      "mid: 68 low: 65 high: 68\n",
      "0x42 38.79\n",
      "0x43 32.77\n",
      "mid: 66 low: 65 high: 66\n",
      "best JETA:- 59.62 best reg: 0x41  or  0x82\n"
     ]
    }
   ],
   "source": [
    "from eye2 import EyeSensor\n",
    "#from f500 import EyeSensor\n",
    "import numpy as np, time\n",
    "import jtoollib as jt\n",
    "\n",
    "from pic_window import *\n",
    "\n",
    "\n",
    "# D-VCOM取值范围，0x00->0x7F， 末位0为MTP，1为DAC\n",
    "measured = {}            # 缓存已测量过的亮度：reg_val -> brightness\n",
    "low, high = 0x00, 0x7F\n",
    "\n",
    "# 1. 实例化传感器对象（根据实际串口号和波特率修改）\n",
    "sensor = EyeSensor(port='COM5', baudrate=115200)\n",
    "\n",
    "# 扫描JI2C\n",
    "devices = jt.scan_devices_sn()\n",
    "# 开启JI2C\n",
    "handle = jt.open_device(devices[0])\n",
    "\n",
    "\n",
    "# 1) 启动后立即显示一张空图，然后动态更新\n",
    "win = NonBlockingImageWindow(\"Demo\", size=(800, 800), fps=10)\n",
    "\n",
    "# # 文件路径\n",
    "# win.update(\"test.jpg\", fmt=\"path\")\n",
    "\n",
    "# RGB数据\n",
    "img = np.zeros((800, 800, 3), dtype=np.uint8)\n",
    "img[:, 0:800:2, 1] = 127\n",
    "win.update(img, fmt=\"rgb\")\n",
    "\n",
    "\n",
    "try:\n",
    "    if 'JETA_flag' not in locals():\n",
    "        sensor.JETAmode()\n",
    "    JETA_flag = 1\n",
    "\n",
    "    while low < high-1:\n",
    "        mid = round((low + high) / 2)\n",
    "\n",
    "        # 测量 f(mid)\n",
    "        if mid not in measured:\n",
    "            jt.i2c_write_no_reg(handle=handle, addr=0x9E, data=[ mid<<1])\n",
    "            measured[mid] = sensor.GetJETA()\n",
    "            print(hex(mid), measured[mid])\n",
    "\n",
    "        # 测量 f(mid+1)\n",
    "        if (mid + 1) not in measured:\n",
    "            jt.i2c_write_no_reg(handle=handle, addr=0x9E, data=[ (mid+1)<<1])\n",
    "            measured[mid + 1] = sensor.GetJETA()\n",
    "            print(hex(mid+1), measured[mid + 1])\n",
    "\n",
    "        # 根据相邻点斜率判断峰值方向\n",
    "        if measured[mid] < measured[mid + 1]:\n",
    "            # 右侧更高，峰值在 (mid+1, high]\n",
    "            low = mid + 1\n",
    "        else:\n",
    "            # 左侧（含 mid）可能有峰值，舍弃右侧\n",
    "            high = mid\n",
    "        \n",
    "        print(\"mid:\",mid,\"low:\",low,\"high:\",high)\n",
    "\n",
    "    result = max([(low,measured[low]), (mid,measured[mid]), (high, measured[high])], key=lambda x: x[1])[0]\n",
    "\n",
    "    # 此时 low == high，即峰值寄存器\n",
    "    peak_reg = low \n",
    "    # 再次确认亮度（可选，measured 已包含）\n",
    "    jt.i2c_write_no_reg(handle=handle, addr=0x9E, data=[ (result)<<1])\n",
    "    best_JETA = sensor.GetJETA()\n",
    "    print(\"best JETA:-\",best_JETA, \"best reg:\",hex(result),\" or \", hex((result)<<1))\n",
    "\n",
    "finally:\n",
    "    jt.jtool.DevClose(handle)\n",
    "    win.stop()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d0eb017d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# CR测试\n",
    "from eye2 import EyeSensor\n",
    "import time\n",
    "\n",
    "#from jtlib import *\n",
    "import jtoollib as jt\n",
    "\n",
    "\n",
    "# 1. 实例化传感器对象（根据实际串口号和波特率修改）\n",
    "sensor = EyeSensor(port='COM7', baudrate=115200)\n",
    "\n",
    "y_l0 = 0\n",
    "y_l255 = 0\n",
    "\n",
    "# 1) 启动后立即显示一张空图，然后动态更新\n",
    "win = NonBlockingImageWindow(\"Demo\", size=(800, 800), fps=10)\n",
    "\n",
    "# # 文件路径\n",
    "# win.update(\"test.jpg\", fmt=\"path\")\n",
    "\n",
    "# RGB数据\n",
    "img = np.zeros((800, 800, 3), dtype=np.uint8)\n",
    "img[:, :, :] = 127\n",
    "win.update(img, fmt=\"rgb\")\n",
    "\n",
    "try:\n",
    "    sensor.XYZmode()\n",
    "    \n",
    "    img[:, :, :] = 255\n",
    "    win.update(img, fmt=\"rgb\")\n",
    "\n",
    "    flag = True\n",
    "    while flag:\n",
    "        try:\n",
    "            x_val, y_val, z_val = sensor.GetXYZ(timeout=0.1)\n",
    "            flag = False\n",
    "        except:\n",
    "            pass\n",
    "\n",
    "    y_l255 = y_val\n",
    "    print(y_l255)\n",
    "\n",
    "    img[:, :, :] = 0\n",
    "    win.update(img, fmt=\"rgb\")\n",
    "\n",
    "    flag = True\n",
    "    while flag:\n",
    "        try:\n",
    "            x_val, y_val, z_val = sensor.GetXYZ(timeout=0.1)\n",
    "            flag = False\n",
    "        except:\n",
    "            pass\n",
    "\n",
    "    y_l0 = y_val\n",
    "    print(y_l0)\n",
    "\n",
    "    print(y_l255/y_l0)\n",
    "\n",
    "\n",
    "\n",
    "finally:\n",
    "    win.stop()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
